﻿using Cms.Core.Infrastructure.Extension;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Cms.Core.Infrastructure.ExpressionUtil
{

   public  class CmsExpressionParser<T>
    {
        private ParameterExpression parameter = Expression.Parameter(typeof(T));

        public Expression<Func<T, bool>> ToExpression(IEnumerable<CmsConditions> conditions)
        {
            conditions = conditions.Where(o => o.IsEmptyOrNull == false && !(o.Value.IsNullOrWhiteSpace()));
            var query = ParseExpressionBody(conditions);
            var lambda = Expression.Lambda<Func<T, bool>>(query, parameter);
            return lambda;
        }
        private Expression ParseExpressionBody(IEnumerable<CmsConditions> conditions)
        {

            if (conditions == null || conditions.Count() == 0)
            {
                return Expression.Constant(true, typeof(bool));
            }
            else if (conditions.Count() == 1)
            {
                return ParseCondition(conditions.First());
            }
            else
            {
                var first = conditions.First();
                var skip = conditions.Skip(1);
                Expression left = ParseCondition(first);
                Expression right = ParseExpressionBody(skip);
                if (first.Connect == ConnectEnum.And)
                {
                    return Expression.AndAlso(left, right);
                }
                else
                {
                    return Expression.OrElse(left, right);
                }
              
            }
        }

        //private static Dictionary<UosoOperatorEnum, Func<Expression, Expression, Expression>> ExpressionDic =
        //     new Dictionary<UosoOperatorEnum, Func<Expression, Expression, Expression>>()
        //     {

        //         [UosoOperatorEnum.Equal] = Expression.Equal,
        //         [UosoOperatorEnum.Greater] = Expression.GreaterThan,
        //         [UosoOperatorEnum.GreaterEqual] = Expression.GreaterThanOrEqual,
        //         [UosoOperatorEnum.Less] = Expression.LessThan,
        //         [UosoOperatorEnum.LessEqual] = Expression.LessThanOrEqual,
        //         [UosoOperatorEnum.NotEqual] = Expression.NotEqual,
        //     };


        private static Dictionary<string, Expression> dic = new Dictionary<string, Expression>();
        private Expression ParseCondition(CmsConditions condition)
        {
            ParameterExpression p = parameter;
            Expression key = Expression.Property(p, condition.Key);
            Expression value = Expression.Constant(condition.Value);
            switch (condition.Operator)
            {
                case CmsOperatorEnum.Contains:
                    return Expression.Call(key, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), value);
                case CmsOperatorEnum.Equal:
                    return Expression.Equal(key, Expression.Convert(value, key.Type));
                case CmsOperatorEnum.Greater:
                    return Expression.GreaterThan(key, Expression.Convert(value, key.Type));
                case CmsOperatorEnum.GreaterEqual:
                    return Expression.GreaterThanOrEqual(key, Expression.Convert(value, key.Type));
                case CmsOperatorEnum.Less:
                    return Expression.LessThan(key, Expression.Convert(value, key.Type));
                case CmsOperatorEnum.LessEqual:
                    return Expression.LessThanOrEqual(key, Expression.Convert(value, key.Type));
                case CmsOperatorEnum.NotEqual:
                    return Expression.NotEqual(key, Expression.Convert(value, key.Type));
                case CmsOperatorEnum.In:
                    return ParaseIn(p, condition);
                case CmsOperatorEnum.Between:
                    return ParaseBetween(p, condition);
                default:
                    throw new NotImplementedException("不支持此操作");
            }
        }





        private Expression ParaseBetween(ParameterExpression parameter, CmsConditions conditions)
        {
            ParameterExpression p = parameter;
            Expression key = Expression.Property(p, conditions.Key);
            var valueArr = conditions.Value.Split(',');
            if (valueArr.Length != 2)
            {
                throw new NotImplementedException("ParaseBetween参数错误");
            }
            try
            {
                int.Parse(valueArr[0]);
                int.Parse(valueArr[1]);
            }
            catch
            {
                throw new NotImplementedException("ParaseBetween参数只能为数字");
            }
            Expression expression = Expression.Constant(true, typeof(bool));
            //开始位置
            Expression startvalue = Expression.Constant(int.Parse(valueArr[0]));
            Expression start = Expression.GreaterThanOrEqual(key, Expression.Convert(startvalue, key.Type));

            Expression endvalue = Expression.Constant(int.Parse(valueArr[1]));
            Expression end = Expression.GreaterThanOrEqual(key, Expression.Convert(endvalue, key.Type));
            return Expression.AndAlso(start, end);
        }

 

        private Expression ParaseIn(ParameterExpression parameter, CmsConditions conditions)
        {
            ParameterExpression p = parameter;
            Expression key = Expression.Property(p, conditions.Key);
            var valueArr = conditions.Value.Split(',');
            Expression expression = Expression.Constant(true, typeof(bool));
            foreach (var itemVal in valueArr)
            {
                Expression value = Expression.Constant(itemVal);
                Expression right = Expression.Equal(key, Expression.Convert(value, key.Type));

                expression = Expression.Or(expression, right);
            }
            return expression;
        }
    }
}
